package impl.comp;

import java.util.concurrent.Executors;

import debug.DebugIFace;
import debug.DebugImpl;

import impl.DataImpl;
import impl.DatabaseImpl;
import impl.LifeManagerImpl;
import impl.agentt.UnePresenceImpl;
import impl.agentt.enseignant.UnEnseignantImpl;
import impl.agentt.etudiant.UnEtudiantImpl;
import impl.agentt.pEns.BehaviourPEns;
import impl.agentt.pEtu.BehaviourPEtu;
import interfaces.agenttCreation.CreateEnseignantIface;
import interfaces.agenttCreation.CreateEtudiantIface;
import interfaces.agenttCreation.CreatePresenceIface;
import message.EDTMessage;
import message.enseignant.InitEnseignantAgent;
import message.etudiant.InitEtudiantAgent;
import mysticedt.Data;
import mysticedt.Database;
import mysticedt.DebugCompo;
import mysticedt.Infr;
import mysticedt.LifeManager;
import mysticedt.PlagesHoraires;
import fr.irit.smac.may.lib.components.messaging.Sender;
import fr.irit.smac.may.lib.components.messaging.SenderImpl;
import fr.irit.smac.may.lib.components.messaging.receiver.AgentRef;
import fr.irit.smac.may.lib.components.messaging.receiver.Receiver;
import fr.irit.smac.may.lib.components.messaging.receiver.ReceiverImpl;
import fr.irit.smac.may.lib.components.meta.Forward;
import fr.irit.smac.may.lib.components.meta.ForwardImpl;
import fr.irit.smac.may.lib.components.scheduling.ExecutorService;
import fr.irit.smac.may.lib.components.scheduling.ExecutorServiceWrapperImpl;
import fr.irit.smac.may.lib.components.scheduling.Scheduler;
import fr.irit.smac.may.lib.components.scheduling.SchedulerImpl;
import fr.irit.smac.may.lib.interfaces.Push;

public class InfrImpl extends Infr {

	// ici je garde une référence vers chacunes des transverses.
	LifeManagerImpl lifemanager;
	ReceiverImpl<EDTMessage> referenceReceiver;
	SenderImpl<EDTMessage, AgentRef> referenceSender;
	SchedulerImpl scheduler;
	DataImpl datat;
	ForwardImpl<DebugIFace> debugForward ;
	
	
	protected volatile long i = 0;

	@Override
	protected CreateEtudiantIface createEtudiantAgent() {
		return new CreateEtudiantIface() {

			public AgentRef createEtudiantAgent() {
				Etudiant agent = new Etudiant(new UnEtudiantImpl(),
						referenceReceiver.new AgentSide("Etu_" + i++),
						referenceSender.new AgentSide(),
						lifemanager.new AgentSide(), scheduler.new AgentSide(),
						datat.new AgentSide(),
						debugForward.new AgentSide());

				agent.start();
				return agent.referenceReceiver().me().pull();
			}
		};
	}

	@Override
	protected CreateEnseignantIface createEnseignantAgent() {
		return new CreateEnseignantIface() {

			public AgentRef createEnseignantAgent() {
				Enseignant agent = new Enseignant(new UnEnseignantImpl(),
						referenceReceiver.new AgentSide("Ens_" + i++),
						referenceSender.new AgentSide(),
						lifemanager.new AgentSide(), scheduler.new AgentSide(),
						datat.new AgentSide(),
						debugForward.new AgentSide());

				agent.start();
				return agent.referenceReceiver().me().pull();
			}
		};
	}

	@Override
	protected CreatePresenceIface createPresenceAgent() {
		return new CreatePresenceIface() {

			public AgentRef createPresenceEtudiantAgent() {
				Presence agent = new Presence(new UnePresenceImpl(
						new BehaviourPEtu()),

				referenceReceiver.new AgentSide("pEtu_" + i++),
						referenceSender.new AgentSide(),
						lifemanager.new AgentSide(), scheduler.new AgentSide(),
						datat.new AgentSide(),
						debugForward.new AgentSide());

				agent.start();
				return agent.referenceReceiver().me().pull();

			}

			public AgentRef createPresenceEnseignantAgent() {
				Presence agent = new Presence(new UnePresenceImpl(
						new BehaviourPEns()),

				referenceReceiver.new AgentSide("pEns_" + i++),
						referenceSender.new AgentSide(),
						lifemanager.new AgentSide(), scheduler.new AgentSide(),
						datat.new AgentSide(),
						debugForward.new AgentSide());

				agent.start();
				return agent.referenceReceiver().me().pull();

			}
		};
	}

	// transverses.
	@Override
	protected LifeManager make_lifeManager() {
		lifemanager = new LifeManagerImpl();
		return lifemanager;
	}

	@Override
	protected Receiver<EDTMessage> make_referenceReceiver() {
		referenceReceiver = new ReceiverImpl<EDTMessage>();
		return referenceReceiver;
	}

	@Override
	protected Sender<EDTMessage, AgentRef> make_referenceSender() {
		referenceSender = new SenderImpl<EDTMessage, AgentRef>();
		return referenceSender;
	}

	@Override
	protected Scheduler make_scheduler() {
		scheduler = new SchedulerImpl();
		return scheduler;
	}

	@Override
	protected Data make_data() {
		datat = new DataImpl();
		return datat;
	}

	@Override
	protected Forward<DebugIFace> make_debugForward() {
		debugForward = new ForwardImpl<DebugIFace>();
		
		return debugForward;
	}
	
	// composants.
	@Override
	protected ExecutorService make_executor() {
		return new ExecutorServiceWrapperImpl(Executors.newFixedThreadPool(8));
	}

	@Override
	protected PlagesHoraires make_ph() {
		return new PlagesHorairesImpl();
	}

	@Override
	protected Database make_db() {
		// TODO Auto-generated method stub
		return new DatabaseImpl();
	}
	@Override
	protected DebugCompo make_debugC() {
		return new DebugImpl(true);
	}

	@Override
	protected Push<String> makeAgentFromDataBase() {
		return new Push<String>() {

			public void push(String thing) {
				db().initSenario().push(thing);
				// the create agents
				for (Integer i : db().pull().getTeacherList()) {

					AgentRef agentEnseignantRef = createEnseignantAgent()
							.createEnseignantAgent();
					db().saveLinkAgentId().saveLinkAgentId(agentEnseignantRef,
							i);

					// informe l'agent qu'il doit maintenant penser à
					// s'initialiser.
					referenceReceiver().deposit().send(
							new InitEnseignantAgent(), agentEnseignantRef);
				}
				System.out.println("Infra --> Creation de "+i+" agent(s) Ens");
				for (Integer studentIDFromDB : db().pull().getStudentList()) {

					AgentRef studentAgentReference = createEtudiantAgent()
							.createEtudiantAgent();
					db().saveLinkAgentId().saveLinkAgentId(
							studentAgentReference, studentIDFromDB);
					// do stuff

					// informe l'agent qu'il doit maintenant penser à
					// s'initialiser.
					referenceReceiver().deposit().send(new InitEtudiantAgent(),
							studentAgentReference);
				}
				System.out.println("Infra --> Creation de "+i+" agent(s) Etu");
			}
		};
	}


}
